package com.jianjun.project.monitor.job;


import cn.hutool.core.thread.ThreadUtil;
import cn.hutool.cron.CronUtil;
import cn.hutool.cron.pattern.parser.PatternParser;
import com.jfinal.aop.Before;
import com.jfinal.kit.Kv;
import com.jfinal.plugin.activerecord.Db;
import com.jfinal.plugin.activerecord.Model;
import com.jfinal.plugin.activerecord.Page;
import com.jfinal.plugin.activerecord.SqlPara;
import com.jfinal.plugin.activerecord.tx.Tx;
import com.jianjun.common.constant.ScheduleConstants;
import com.jianjun.common.util.job.ScheduleUtils;
import com.jianjun.project.common.model.SysJob;

import java.util.Date;
import java.util.List;

/**
 * 定时任务调度信息 服务层
 *
 * @author source
 */

public class SysJobService {
    private final SysJob dao = new SysJob().dao();

    /**
     * 项目启动时，初始化定时器 主要是防止手动修改数据库导致未同步到定时任务处理（注：不能手动修改数据库ID和任务组名，否则会导致脏数据）
     */
    public void init() {
        //使用deamon模式，
        CronUtil.start(true);
        List<SysJob> jobList = dao.findAll();
        for (SysJob job : jobList) {
            ScheduleUtils.createScheduleJob(job);
        }
    }

    public Page<SysJob> paginate(SysJob model) {
        SqlPara sqlParaDb = Db.getSqlPara("querySysJob", Kv.by("cond", model.toMap()).set(model.getColumnAsc()));
        return dao.paginate(model.getPageNum(), model.getPageSize(), sqlParaDb);
    }

    /**
     * 获取quartz调度器的计划任务列表
     */
    public List<SysJob> selectJobList(Model<SysJob> model) {
        SqlPara sqlParaDb = Db.getSqlPara("querySysJob", Kv.by("cond", model.toMap()));
        return dao.find(sqlParaDb);
    }

    /**
     * 通过调度任务ID查询调度信息
     *
     * @param jobId 调度任务ID
     * @return 调度任务对象信息
     */
    public SysJob selectJobById(Long jobId) {
        SysJob model = new SysJob();
        model.setJobId(jobId);
        SqlPara sqlParaDb = Db.getSqlPara("querySysJob", Kv.by("cond", model.toMap()));
        return dao.findFirst(sqlParaDb);
    }

    /**
     * 批量删除调度信息
     *
     * @param jobIds 需要删除的任务ID
     */
    @Before(Tx.class)
    public void deleteJobByIds(Long[] jobIds) {
        for (Long jobId : jobIds) {
            SysJob job = selectJobById(jobId);
            deleteJob(job);
        }
    }


    /**
     * 删除任务后，所对应的trigger也将被删除
     *
     * @param job 调度信息
     */
    public boolean deleteJob(SysJob job) {
        Long jobId = job.getJobId();
        String jobGroup = job.getJobGroup();
        boolean res = selectJobById(jobId).delete();
        if (res) {
            CronUtil.remove(ScheduleUtils.getJobKey(jobId, jobGroup));
        }
        return res;
    }


    /**
     * 恢复任务
     *
     * @param job 调度信息
     */
    public boolean resumeJob(SysJob job) {
        job.setStatus(ScheduleConstants.Status.NORMAL.getValue());
        boolean res = job.update();
        if (res) {
            ScheduleUtils.createScheduleJob(job);
        }
        return res;
    }


    /**
     * 任务调度状态修改
     *
     * @param job 调度信息
     */
    public boolean changeStatus(SysJob job) {
        boolean res = false;
        String status = job.getStatus();
        Long jobId = job.getJobId();
        String jobGroup = job.getJobGroup();
        if (ScheduleConstants.Status.NORMAL.getValue().equals(status)) {
            res = resumeJob(job);
        } else if (ScheduleConstants.Status.PAUSE.getValue().equals(status)) {
            CronUtil.remove(ScheduleUtils.getJobKey(jobId, jobGroup));
            res = job.update();
        }
        return res;
    }

    /**
     * 立即运行任务
     *
     * @param job 调度信息
     */
    public boolean run(SysJob job) {
        boolean result = true;
        ThreadUtil.execAsync(() -> ScheduleUtils.executeJob(job));
        return result;
    }

    /**
     * 新增任务
     *
     * @param job 调度信息 调度信息
     */
    public boolean insertJob(SysJob job) {
        job.setStatus(ScheduleConstants.Status.PAUSE.getValue());
        job.setCreateTime(new Date());
        return job.save();
    }

    /**
     * 更新任务的时间表达式
     *
     * @param job 调度信息
     */
    public boolean updateJob(SysJob job) {
        job.setUpdateTime(new Date());
        boolean res = job.update();
        if (res) {
            ScheduleUtils.createScheduleJob(job);
        }
        return res;
    }


    /**
     * 校验cron表达式是否有效
     *
     * @param cronExpression 表达式
     * @return 结果
     */
    public boolean checkCronExpressionIsValid(String cronExpression) {
        return !PatternParser.parse(cronExpression).isEmpty();
    }
}